import hashlib
import random
from abc import ABC, abstractmethod

import ddddocr
import requests
from typing import Optional, Dict

from config import Config
from loguru import logger

from app.utils.create_session import create_new_session


# 抽象基础组件
class CaptchaProcessor(ABC):
    @abstractmethod
    def get_captcha(self, image_data: bytes) -> str:
        """验证码识别抽象方法"""
        pass


class OCRCaptchaProcessor(CaptchaProcessor):
    def __init__(self):
        self.ocr = ddddocr.DdddOcr(show_ad=False)

    def get_captcha(self, image_data: bytes) -> str:
        return self.ocr.classification(image_data)


# 认证策略接口
class AuthStrategy(ABC):
    @abstractmethod
    def authenticate(self) -> Optional[str]:
        """执行认证并返回令牌"""
        pass


# 具体CAS认证实现
class CASLoginStrategy(AuthStrategy):
    def __init__(self, env: str, username: str, password: str):
        self.env = env
        self.session = create_new_session()
        self.username = username
        self.password = password
        self.ocr_processor = OCRCaptchaProcessor()
        # 请求头配置
        self.headers = {
            "content-type": "application/x-www-form-urlencoded",
            "upgrade-insecure-requests": "1",
            "cache-control": "max-age=0",
            "content-length": "252",
            "priority": "u=0, i",
            "sec-ch-ua": '"Chromium";v="136", "Microsoft Edge";v="136", "Not.A/Brand";v="99"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "Windows",
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "sec-gpc": "1",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67",
        }

    @staticmethod
    def _get_random_number():
        number = random.randint(1, 999)
        return number + 3000

    def _get_url(self):
        if "pro" == self.env:
            return Config.PROD_URL
        elif "test" == self.env:
            return Config.TEST_URL
        else:
            return None

    def _get_captcha(self) -> str:
        """获取并识别验证码"""
        captcha_url = f"{self._get_url()}/cas/captcha?"
        params = f"time={self._get_random_number()}"
        response = self.session.get(url=captcha_url, params=params)
        return self.ocr_processor.get_captcha(response.content)

    def _build_payload(self, captcha: str) -> Dict:
        """构造动态请求参数"""
        md5_hash = hashlib.md5()
        md5_hash.update(self.password.encode("utf-8"))
        password = md5_hash.hexdigest()
        return {
            "account": self.username,
            "password": password,
            "captcha": captcha,
            "lt": "LT-10012-BxTnDjV0sd2eNRa45kGT22oJ9p9ECi",
            "execution": "e4s1",
            "_eventId": "submit",
        }

    def authenticate(self) -> Optional[str]:
        """执行认证流程"""
        try:
            # 获取验证码
            captcha = self._get_captcha()
            logger.info(f"Captcha: {captcha}")
            if not captcha:
                raise ValueError("Captcha recognition failed")
            # 构造请求参数
            payload = self._build_payload(captcha)
            # 发送登录请求
            response = self.session.post(
                f"{self._get_url()}/cas/login",
                headers=self.headers,
                data=payload,
                allow_redirects=False,
            )
            if "test" == self.env:
                return response.cookies.get("test_cas_access_token")
            elif "pro" == self.env:
                return response.cookies.get("cas_access_token")
            else:
                return None
        except requests.RequestException as e:
            logger.info(f"Authentication failed: {e}")
            return None
        finally:
            self.session.close()


# 客户端调用示例
if __name__ == "__main__":
    # 依赖配置
    env = "pro"
    username = "BQ_admin"
    encrypted_pwd = "123"
    # 构造处理器
    auth_strategy = CASLoginStrategy(env=env, username=username, password=encrypted_pwd)
    # 执行认证
    token = auth_strategy.authenticate()
    print("Obtained token:", token)
